package com.jerei.web.utils;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.util.Calendar;

import org.apache.commons.codec.binary.Base64;

public class LicenseUtils {

	public static void main(String[] args) throws IOException {
		// 公钥（放在项目底下，开发给客户）
		String pubKeyText = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxIuh1uRNE/G2uhxv+h4826dC3+7VHTNd8JzT50DDRMrFZiubO2NA/eRoL1sZo1qkIxpFt+zXfRpkgnPpK0JmT4aAlZC2eGLWHC1n1soqnkM2Ss2RGqS7hAGcShWuwbyiHFyy6FEAgTo7Ju2JvO5NMegNzTSpnyx7ssiJ4qH+NqQIDAQAB";
		// 私钥（捷瑞方做保留，用于生成签名）
		String priKeyText = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALEi6HW5E0T8ba6HG/6Hjzbp0Lf7tUdM13wnNPnQMNEysVmK5s7Y0D95GgvWxmjWqQjGkW37Nd9GmSCc+krQmZPhoCVkLZ4YtYcLWfWyiqeQzZKzZEapLuEAZxKFa7BvKIcXLLoUQCBOjsm7Ym87k0x6A3NNKmfLHuyyIniof42pAgMBAAECgYAsf+iGKoh8vC2Rur99ofCIixS0I7fWwacguXjFiVe6NlH3fL2fGTi3uWShtMMDc2njmn7Ocl2GSeYOG2GFigIKh/ovPZT2Z+TH/6T+T2aFINnAgpuNREtNwdpWiHCkyKA9zYO8hRmK/8KYOVOGmdrjxFb+bcYbNjQQRDCiazH4AQJBAP0xECdTFCeuDtEgevCHN9Fx/0is3BowFwXvWQTWTBsTf1AzF6/5HxoXqR4lbeREe5uEC4QVAq7rFhiPuR+puRECQQCzGeLcwdja9k4dKdZ9xWsnnbtHc0BEeagwFFQ0GEvNqPUnOyhZfD5C7qtAQjsZlgFk7FSODQua2G76FoBobMsZAkAq2SnFre6kRHWneJq1p/yPSn6MewyItgi/bWEgS2/3yRXrqanhkwRrcwOg4W62icxtZixYvwGEPq6vm2sV67AxAkEAq7vBnb4+as7MXgh1BEpdkjIblsp7MG2bCOclSoKVhRFiaQi/ivaoWNOz37ziIImGsrgt57u4ifTIjQMwg3D2WQJBAI2OgaSjnc97H4+WlSa5U0ZcPmvkWT42UuwyHqaBK6LpbWAImZlbR/cujj9BskMJJt6mdFh4m42LB2myq6cppKI=";
		// 授权文件地址
		File licenseFile = new File("E:/license");
		// 授权MAC地址,授权有效期(-1为不限制),最大用户数量(-1为不限制)
		String inStr = "28D244A5B559,20161118,-1";
		// 生成授权文件
		write(licenseFile, inStr, priKeyText);
		// 授权验证，如不通过，会退出系统
		license(licenseFile, pubKeyText);
	}

	/**
	 * 验证授权
	 * 
	 * @param file
	 *            授权文件地址
	 */
	protected static void license(File file, String pubKeyText) {
		try {
			String license = read(file, pubKeyText);
			String mac = mac();
			mac = mac.replaceAll("-", "");
			String[] arr = license.split(",");
			String _mac = arr[0];
			String _date = arr[1];
			// 如果mac地址不一致，退出系统
			if (!_mac.equals(mac)) {
				System.out.print("退出系统");
				System.exit(0);
			}
			SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
			Long _licenseDate = sdf.parse(_date).getTime();
			Long _nowDate = sdf.parse(
					sdf.format(Calendar.getInstance().getTime())).getTime();
			// 如果已到有效期，退出系统
			if (_licenseDate.compareTo(_nowDate) < 0) {
				System.out.print("退出系统");
				System.exit(0);
			}
		} catch (Exception e) {
			System.out.print("退出系统");
			System.exit(0);
		}
	}

	private static String read(File f, String pubKeyText) throws IOException {
		DataInputStream in = new DataInputStream(new BufferedInputStream(
				new FileInputStream(f.getAbsolutePath())));
		// 取出内容长度
		int len = in.readInt();
		byte[] b = new byte[len];
		// 根据内容长度取出内容
		in.read(b, 0, len);
		String content = new String(b);
		// 取出签名长度
		len = in.readInt();
		byte[] sign = new byte[len];
		// 读取签名
		in.read(sign);
		// 根据钥匙验证签名是否正确
		boolean signOk = SignProvider.verify(pubKeyText.getBytes(), content,
				sign);
		if (signOk) {
			return content;
		}
		return null;
	}

	private static void write(File file, String inStr, String priKeyText)
			throws IOException {
		byte[] sign = Signaturer.sign(priKeyText.getBytes(), inStr);
		DataOutputStream out = new DataOutputStream(new FileOutputStream(
				file.getAbsolutePath()));
		// 写入内容长度
		out.writeInt(inStr.length());
		// 写入内容
		out.write(inStr.getBytes());
		// 写入签名长度
		out.writeInt(sign.length);
		// 写入签名
		out.write(sign);
		out.close();
	}

	private static String mac() throws SocketException, UnknownHostException {
		InetAddress ia = InetAddress.getLocalHost();
		byte[] mac = NetworkInterface.getByInetAddress(ia).getHardwareAddress();
		StringBuffer sb = new StringBuffer("");
		for (int i = 0; i < mac.length; i++) {
			if (i != 0) {
				sb.append("-");
			}
			// 字节转换为整数
			int temp = mac[i] & 0xff;
			String str = Integer.toHexString(temp);
			if (str.length() == 1) {
				sb.append("0" + str);
			} else {
				sb.append(str);
			}
		}
		return sb.toString().toUpperCase();
	}

}

class SignProvider {
	private SignProvider() {

	}

	public static boolean verify(byte[] pubKeyText, String plainText,
			byte[] signText) {
		try {
			// 解密由base64编码的公钥,并构造X509EncodedKeySpec对象
			X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(
					Base64.decodeBase64(pubKeyText));
			// RSA对称加密算法
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			// 取公钥匙对象
			PublicKey pubKey = keyFactory.generatePublic(bobPubKeySpec);
			// 解密由base64编码的数字签名
			byte[] signed = Base64.decodeBase64(signText);
			Signature signatureChecker = Signature.getInstance("MD5withRSA");
			signatureChecker.initVerify(pubKey);
			signatureChecker.update(plainText.getBytes());
			// 验证签名是否正常
			if (signatureChecker.verify(signed))
				return true;
			else
				return false;
		} catch (Throwable e) {
			System.out.println("校验签名失败");
			e.printStackTrace();
			return false;
		}
	}
}

class KeyGenerater {
	private byte[] priKey;
	private byte[] pubKey;

	public void generater() {
		try {
			KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
			SecureRandom secrand = new SecureRandom();
			secrand.setSeed("www.jerei.com".getBytes());
			keygen.initialize(1024, secrand);
			KeyPair keys = keygen.genKeyPair();
			PublicKey pubkey = keys.getPublic();
			PrivateKey prikey = keys.getPrivate();
			pubKey = Base64.encodeBase64(pubkey.getEncoded());
			priKey = Base64.encodeBase64(prikey.getEncoded());
			System.out.println("pubKey = " + new String(pubKey));
			System.out.println("priKey = " + new String(priKey));
		} catch (java.lang.Exception e) {
			System.out.println("生成密钥对失败");
			e.printStackTrace();
		}
	}

	public byte[] getPriKey() {
		return priKey;
	}

	public byte[] getPubKey() {

		return pubKey;

	}
}

class Signaturer {
	public static byte[] sign(byte[] priKeyText, String plainText) {
		try {
			PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
					Base64.decodeBase64(priKeyText));
			KeyFactory keyf = KeyFactory.getInstance("RSA");
			PrivateKey prikey = keyf.generatePrivate(priPKCS8);
			Signature signet = java.security.Signature
					.getInstance("MD5withRSA");
			signet.initSign(prikey);
			signet.update(plainText.getBytes());
			byte[] signed = Base64.encodeBase64(signet.sign());
			return signed;
		} catch (java.lang.Exception e) {
			System.out.println("签名失败");
			e.printStackTrace();
		}
		return null;
	}
}